#include <QtGui>

#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <OgreRenderWindow.h>
#include <OgreViewport.h>
#include <OgreOverlayManager.h>
#include <OgreOverlayElement.h>
#include <OgreStringConverter.h>
#include <OgreResourceGroupManager.h>
#include <OgreConfigFile.h>

#include <vld.h>

#include "OgreWidget.h"


//----------------------------------------------------------------------------------------------------------------------
OgreWidget::OgreWidget(QWidget* parent) :
	QWidget(parent),
	mOgreRoot(NULL),
	mRenderWindow(NULL),
	mCamera(NULL),
	mSceneManager(NULL)
{
	setAttribute( Qt::WA_PaintOnScreen, true );
	setAttribute( Qt::WA_NoBackground );
}

//----------------------------------------------------------------------------------------------------------------------
OgreWidget::~OgreWidget()
{
	mRenderWindow->removeViewport(mRenderWindow->getViewport(0)->getZOrder());
	mSceneManager->destroyCamera(mCamera);
	mOgreRoot->destroySceneManager(mSceneManager);
	mRenderWindow->destroy();
	mOgreRoot->shutdown();
	delete mOgreRoot;
}

//----------------------------------------------------------------------------------------------------------------------
bool OgreWidget::initialize()
{
	mOgreRoot = new Ogre::Root("Plugins.cfg", "editor.cfg", "log.txt");

	// set render system to direct3d
	Ogre::RenderSystemList* rendererList = mOgreRoot->getAvailableRenderers();
	Ogre::RenderSystem* renderSystem = mOgreRoot->getRenderSystemByName("Direct3D9 Rendering Subsystem");

	if(renderSystem == NULL)
		return false;

	mOgreRoot->setRenderSystem(renderSystem);

	// config render system
	renderSystem->setConfigOption("Full Screen", "No");
	renderSystem->setConfigOption("Video Mode", "1024 x 768 @ 32-bit colour");
	
	mOgreRoot->saveConfig();

	// Load resource paths from config file
	Ogre::ConfigFile cf;
	cf.load("resources.cfg");

	// Go through all sections & settings in the file
	Ogre::ConfigFile::SectionIterator seci = cf.getSectionIterator();

	Ogre::String secName, typeName, archName;
	while (seci.hasMoreElements())
	{
		secName = seci.peekNextKey();
		Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
		Ogre::ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i)
		{
			typeName = i->first;
			archName = i->second;
			Ogre::ResourceGroupManager::getSingleton().addResourceLocation(
				archName, typeName, secName);
		}
	}
	mRenderWindow = mOgreRoot->initialise(false);

	// create render window
	Ogre::String winHandle;
	winHandle = Ogre::StringConverter::toString((int)winId());
	Ogre::NameValuePairList param;
	param["externalWindowHandle"] = winHandle;
	
	mRenderWindow = mOgreRoot->createRenderWindow("OgreWidget", 
													this->width(),
													this->height(),
													false,
													&param);
	mRenderWindow->setActive(true);

	Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();	

	// initialise Ogre
	mSceneManager = mOgreRoot->createSceneManager(Ogre::ST_GENERIC);

	mSceneManager->setAmbientLight(Ogre::ColourValue(1.0f, 1.0f, 1.0f, 1.0f));

	mCamera = mSceneManager->createCamera("QOgreWidget_Cam");
	mCamera->setPosition(Ogre::Vector3(0.0f, 1.0f, 0.0f));
	mCamera->lookAt(Ogre::Vector3(0.0f, 0.0f, 0.0f));
	mCamera->setNearClipDistance(1.0f);

	Ogre::Viewport* viewPort = mRenderWindow->addViewport(mCamera);
	viewPort->setBackgroundColour(Ogre::ColourValue(0.0f, 0.0f, 0.0f, 1.0f));

	return true;
}

//----------------------------------------------------------------------------------------------------------------------
void OgreWidget::paintEvent(QPaintEvent* event)
{
	mOgreRoot->renderOneFrame();
	updateStats();
	update();
}

//----------------------------------------------------------------------------------------------------------------------
void OgreWidget::updateStats(void)
{
	static Ogre::String currFps = "Current FPS: ";
	static Ogre::String avgFps = "Average FPS: ";
	static Ogre::String bestFps = "Best FPS: ";
	static Ogre::String worstFps = "Worst FPS: ";
	static Ogre::String tris = "Triangle Count: ";

	// update stats when necessary
	Ogre::OverlayElement* guiAvg = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/AverageFps");
	Ogre::OverlayElement* guiCurr = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/CurrFps");
	Ogre::OverlayElement* guiBest = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/BestFps");
	Ogre::OverlayElement* guiWorst = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/WorstFps");

	guiAvg->setCaption(avgFps + Ogre::StringConverter::toString(mRenderWindow->getAverageFPS()));
	guiCurr->setCaption(currFps + Ogre::StringConverter::toString(mRenderWindow->getLastFPS()));
	guiBest->setCaption(bestFps + Ogre::StringConverter::toString(mRenderWindow->getBestFPS())
		+ " " +Ogre::StringConverter::toString(mRenderWindow->getBestFrameTime())+" ms");
	guiWorst->setCaption(worstFps + Ogre::StringConverter::toString(mRenderWindow->getWorstFPS())
		+ " " + Ogre::StringConverter::toString(mRenderWindow->getWorstFrameTime())+" ms");

	Ogre::OverlayElement* guiTris = Ogre::OverlayManager::getSingleton().getOverlayElement("Core/NumTris");
	guiTris->setCaption(tris + Ogre::StringConverter::toString(mRenderWindow->getTriangleCount()));
}

//----------------------------------------------------------------------------------------------------------------------
void OgreWidget::showDebugOverlay(bool show)
{   
	Ogre::Overlay* o = Ogre::OverlayManager::getSingleton().getByName("Core/DebugOverlay");
	if (!o)
		OGRE_EXCEPT( Ogre::Exception::ERR_ITEM_NOT_FOUND, "Could not find overlay Core/DebugOverlay",
		"showDebugOverlay" );
	if (show)
		o->show();
	else
		o->hide();
}

//----------------------------------------------------------------------------------------------------------------------
void OgreWidget::resizeEvent(QResizeEvent* event)
{
	mRenderWindow->windowMovedOrResized();
}

//----------------------------------------------------------------------------------------------------------------------
QSize OgreWidget::minimumSizeHint() const
{
	return QSize(640, 480);
}